#基础特征计算类
import time

import pandas as pd

from Utils.DataLoaderAndSaver import DataLoaderAndSaver
from Utils.calFeatures import calLargerThanMas, closeUpPenetrateMas, calSTDS, calLessThanDays, calQuantile, calIncrease, \
    getMaOrder, maIncreaseDays, closeIncreaseDays, masUpPenetrate, volRatio, volIncreaseDays, decreaseFromMaxRecent, \
    increaseFromMinRecent, calMas, calAmplitude, calMinMaxRatio, isRecentDaysMin, isRecentDaysMax, recentDaysMax, \
    recentDaysMin, getCloseDF, calAroundMA, calSunDays, calSunDaysRatio, calRecentSunDays, calRecentNegativeDays, \
    closeDecreaseDays, calRecentSunDaysIncrease, calRecentNegativeDaysDecrease, closeUpPenetrateMa250, calHANegDays, \
    calHASunDays, HAInvert, closeInvert


class FeatureCalculation:
    def __init__(self,daysBefore1=0,daysBefore2=1,yearsBefore=4):
        # 基本的配置信信息,以及加载数据
        # self.increaseTable = 'table_basic_features'
        self.dataLoaderAndSaver = DataLoaderAndSaver(
            daysBefore1=daysBefore1,
            daysBefore2=daysBefore2,
            yearsBefore=yearsBefore,
            reload=False)
        self.codes = set(list(self.dataLoaderAndSaver.allstocks.index))
        self.dailyprices = self.dataLoaderAndSaver.loadDailyPrices()
        self.dailyprices.index=self.dailyprices['date']

    def calFeatures(self):
        maDays=[5,10,20,30,40,50,60,70,80,90,100,120,122,150,180,200,244,250]
        quantileDays=[30,40,50,60,90,100,122,244,366,488,610,732]
        increaseDays = [3, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 122, 150, 180, 200, 244, 250, 300, 366]
        recentDays=[5,10,20,30, 40, 50, 60, 70, 80, 90, 100, 120, 122, 150, 180, 200, 244, 250, 300, 366]
        count=0
        errorcode=[]
        start=time.time()
        tableName = ('daily_features_' + self.dataLoaderAndSaver.todayDate + '_v5').replace('-', '_')
        print(tableName)
        for code in self.codes:
            try:
                print(code)
                dailyprices=self.dailyprices[self.dailyprices['code'] == code]
                if len(dailyprices)==0:
                    continue
                closeDF=getCloseDF(dailyprices,code)
                largerThanMasDF=calLargerThanMas(dailyprices,code,maDays,'larger_')
                closeUpPenetrateMasDF=closeUpPenetrateMas(dailyprices,code,maDays,'uppenetrate_')
                masDF=calMas(dailyprices,code,maDays,'ma_')
                closestdDF = calSTDS(dailyprices, code, maDays, 'close', 'closestd_')
                volstdDF=calSTDS(dailyprices,code,maDays,'volume','volstd_')
                moneystdDF = calSTDS(dailyprices, code, maDays, 'money', 'moneystd_')
                lessThanDF=calLessThanDays(dailyprices,code,[120,250],'lessthan_')
                quantileDF=calQuantile(dailyprices,code,quantileDays,'quant_')
                increaseDF=calIncrease(dailyprices,code,increaseDays,'increase_')
                # ismaOrderDF=getMaOrder(dailyprices,code,[5,10,20,30],'isma_v1')
                increaseMaDF=maIncreaseDays(dailyprices,code,maDays,'ma_increa_')
                closeIncreaseDF=closeIncreaseDays(dailyprices,code,'close_increa_')
                closeDecreaseDF = closeDecreaseDays(dailyprices, code, 'close_decrea_')
                masUpPenetrateDF0 = masUpPenetrate(dailyprices, code, 5, 20, 'ma_')
                masUpPenetrateDF1=masUpPenetrate(dailyprices,code,5,30,'ma_')
                masUpPenetrateDF2 = masUpPenetrate(dailyprices, code, 5, 60, 'ma_')
                masUpPenetrateDF3 = masUpPenetrate(dailyprices, code, 5, 90, 'ma_')
                masUpPenetrateDF4 = masUpPenetrate(dailyprices, code, 5, 120, 'ma_')
                masUpPenetrateDF5 = masUpPenetrate(dailyprices, code, 30, 60, 'ma_')
                masUpPenetrateDF6 = masUpPenetrate(dailyprices, code, 30, 90, 'ma_')
                masUpPenetrateDF7 = masUpPenetrate(dailyprices, code, 30, 120, 'ma_')
                masUpPenetrateDF8 = masUpPenetrate(dailyprices, code, 90, 120, 'ma_')
                masUpPenetrateDF9 = masUpPenetrate(dailyprices, code, 90, 250, 'ma_')
                masUpPenetrateDF10 = masUpPenetrate(dailyprices, code, 120, 250, 'ma_')
                volratioDF=volRatio(dailyprices,code,'volratio')
                volIncreaseDF=volIncreaseDays(dailyprices,code,'volincreasedays')
                decreaseFromMaxRecentDF=decreaseFromMaxRecent(dailyprices,code,recentDays,'decrease_from_max_')
                increaseFromMinRecentDF=increaseFromMinRecent(dailyprices,code,recentDays,'increase_from_min_')
                ampDF=calAmplitude(dailyprices, code, maDays,'amplitude_')
                minmaxRatioDF=calMinMaxRatio(dailyprices, code, maDays,'minmax_ratio_')
                isRecentDaysMinDF=isRecentDaysMin(dailyprices, code, maDays,'recent_min_')
                isRecentDaysMaxDF = isRecentDaysMax(dailyprices, code, maDays, 'recent_max_')
                recentDaysMinDF=recentDaysMin(dailyprices, code, maDays, 'recent_minclose_')
                recentDaysMaxDF = recentDaysMax(dailyprices, code, maDays, 'recent_maxclose_')
                aroundMADF=calAroundMA(dailyprices,code,488,'around_250')
                sundaysDF=calSunDays(dailyprices,code,recentDays,'sundays_')
                sundaysRatioDF = calSunDaysRatio(dailyprices, code, recentDays, 'sundays_ratio_')
                recentSunDaysDF = calRecentSunDays(dailyprices, code, 'recent_sundays')
                recentSunDaysIncDF = calRecentSunDaysIncrease(dailyprices, code, 'recent_sundays_')
                negDaysDF = calRecentNegativeDays(dailyprices, code, 'recent_neg_days')
                negDaysDecDF = calRecentNegativeDaysDecrease(dailyprices, code, 'recent_neg_days_')
                closeUpPenetrateMaDF=closeUpPenetrateMa250(dailyprices, code, 'uppenetrate_250_increase')
                haNegDaysDF = calHANegDays(dailyprices, code, 'ha_negdays')
                haSunDaysDF = calHASunDays(dailyprices, code, 'ha_sundays')
                haInvertDF=HAInvert(dailyprices, code, 'ha_invert_days')
                closeInvertDF=closeInvert(dailyprices, code, 'close_invert')
                # print(lessThanDF)
                # print(quantileDF)
                finalDF = pd.concat([
                    closeDF,
                    largerThanMasDF, closeUpPenetrateMasDF, masDF,
                    closestdDF,
                    volstdDF, moneystdDF,
                    lessThanDF, quantileDF, increaseDF, increaseMaDF,
                    closeIncreaseDF, closeDecreaseDF,
                    masUpPenetrateDF1, masUpPenetrateDF2, masUpPenetrateDF3, masUpPenetrateDF4, masUpPenetrateDF5,
                    masUpPenetrateDF6, masUpPenetrateDF7,
                    masUpPenetrateDF8, masUpPenetrateDF9, masUpPenetrateDF10,
                    volratioDF, volIncreaseDF, decreaseFromMaxRecentDF, increaseFromMinRecentDF,
                    ampDF,
                    minmaxRatioDF,
                    isRecentDaysMinDF, isRecentDaysMaxDF,
                    recentDaysMinDF, recentDaysMaxDF,
                    aroundMADF,
                    sundaysDF, sundaysRatioDF, recentSunDaysDF, recentSunDaysIncDF,
                    negDaysDF,
                    negDaysDecDF,
                    closeUpPenetrateMaDF,
                    haNegDaysDF,haSunDaysDF,
                    haInvertDF,closeInvertDF
                ], axis=1)
                code=list(finalDF.index)[0]
                finalDF.insert(0,'code',code)
                finalDF.insert(0,'date',self.dataLoaderAndSaver.todayDate)
            # print(largerThanMasDF,closeUpPenetrateMasDF,volstdDF,moneystdDF,lessThanDF,
            #       quantileDF,increaseDF,ismaOrderDF,increaseMaDF,closeIncreaseDF,
            #       masUpPenetrateDF,
            #       volratioDF, volIncreaseDF, decreaseFromMaxRecentDF, increaseFromMinRecentDF
            #       )
                print(finalDF,finalDF.shape)
                print(','.join(finalDF.columns))
                self.dataLoaderAndSaver.saveData(tableName,finalDF)
            except:
                print(code,'有误')
                errorcode.append(code)
            count = count + 1
            print(count,'of',len(self.codes))
            end=time.time()
            timeconsumption=end-start
        print('花费时间:%.2f秒,%.2f分钟,%.2f小时'%(timeconsumption,timeconsumption/60,timeconsumption/3600))
        print(errorcode)

fc=FeatureCalculation(-1,0)
fc.calFeatures()
